"""SQL预处理命令模块"""

import argparse
from pathlib import Path
from src.core.command import Command
from src.service.preprocess.preprocess_sql_service import SQLPreprocessService
from src.base.sql_file_utils import SQLFileUtils
from src.base.registry import bera
from src.base.project_config import ProjectConfig
from src.base.sql_utils.sql_path_utils import SQLPathUtils
from typing import Optional, Callable
import re

class PreprocessSQLCommand(Command):
    """SQL预处理命令

    预处理SQL文件，提取标记信息并生成格式化的SQL。
    支持三种输入模式：
    1. 目录模式(-d): 处理目录下的所有SQL文件
    2. 文件路径模式(-f): 处理指定的SQL文件
    3. 文件名模式(-n): 处理标准目录下的SQL文件

    输出目录结构：
    - {output}/tables/{name}/
      - origin.auto.sql: 带标记的原始SQL
      - mark.auto.json: 提取的标记信息
      - formatted.auto.sql: 格式化后的SQL
    """

    def __init__(self):
        super().__init__()
        self.name = "preprocess-sql"
        self.group = "SQL处理"
        self.preprocessor = SQLPreprocessService()

    def add_arguments(self, parser: argparse.ArgumentParser) -> None:
        """添加命令参数"""
        # 添加通用参数
        SQLFileUtils.add_arguments(parser)
        # 添加命令特有参数
        parser.add_argument('--format-create', dest='format_create', action='store_true',
                          help='格式化 CREATE TABLE 语句')
        parser.add_argument('--format-insert', dest='format_insert', action='store_true',
                          help='格式化 INSERT 语句')

    def execute(self, args: argparse.Namespace, callback: Optional[Callable[[], None]] = None) -> None:
        """执行命令"""
        try:
            bera.logger.info("开始执行preprocess-sql命令")

            # 先初始化项目配置
            ProjectConfig.init(args.project_dir)

            # 添加项目配置的sql-dir到搜索路径
            sql_dir = str(ProjectConfig.get_sql_dir())
            bera.logger.debug(f"添加项目配置的SQL目录到搜索路径: {sql_dir}")
            SQLFileUtils.add_search_path(sql_dir)

            # 执行callback
            if callback:
                callback()

            # 使用新的统一输入模式处理
            SQLFileUtils.execute_file_processing(args, self._process_sql_file)

            bera.logger.info("preprocess-sql命令执行完成")

        except Exception as e:
            bera.logger.error(f"preprocess-sql命令执行失败: {str(e)}")
            if args.verbose:
                import traceback
                traceback.print_exc()
            raise

    def _process_sql_file(self, filepath: str, args: argparse.Namespace) -> None:
        """处理单个SQL文件

        Args:
            filepath: SQL文件路径
            args: 命令行参数
        """
        try:
            # 从文件路径获取表名
            table_name = Path(filepath).stem
            bera.logger.info(f"处理表: {table_name}")

            # 获取输出目录
            output_dir = SQLFileUtils.get_output_table_dir(table_name)
            bera.logger.debug(f"输出目录: {output_dir}")
            SQLFileUtils.ensure_directory(output_dir)

            # 获取配置目录
            config_dir = SQLFileUtils.get_output_merge_dir(table_name)
            bera.logger.debug(f"配置目录: {config_dir}")
            SQLFileUtils.ensure_directory(config_dir)

            # 读取SQL文件
            sql_content = SQLFileUtils.read_sql_file(filepath)
            if not sql_content.strip():
                raise ValueError(f"SQL文件为空: {filepath}")

            # 检查标记区数量
            begin_markers = re.findall(r"--\s*@miaoma-begin", sql_content, re.IGNORECASE)
            if len(begin_markers) > 1:
                raise ValueError(f"SQL文件中存在多个标记区开始标记(-- @miaoma-begin): {filepath}")

            # 提取标记区内容: -- @miaoma-begin ... -- @miaoma-end
            pattern = r"--\s*@miaoma-begin(.*?)--\s*@miaoma-end"
            match = re.search(pattern, sql_content, re.DOTALL | re.IGNORECASE)
            if match:
                miaoma_block = match.group(1).strip()
                if not miaoma_block:
                    raise ValueError(f"标记区内容为空: {filepath}")
                sql_to_process = miaoma_block
            else:
                sql_to_process = sql_content

            # 预处理SQL
            bera.logger.info("开始预处理SQL")
            self.preprocessor = SQLPreprocessService(
                format_create_table=args.format_create,
                format_insert=args.format_insert
            )
            result = self.preprocessor.preprocess(sql_to_process)
            bera.logger.info("SQL预处理完成")

            # 构建带标记的SQL
            marked_sql = []
            business_name = result.table.get("business_name", "")
            config_formats = result.table.get("config_formats", [])
            enums = {name: info.get("enum_options", {})
                    for name, info in result.columns.items()
                    if "enum_options" in info}

            if business_name:
                marked_sql.append(f"-- @business_name: {business_name}")
            if config_formats:
                marked_sql.append(f"-- @config: {', '.join(config_formats)}")
            for field_name, enum_values in enums.items():
                # 将enum_values转换为字符串
                enum_str = " ".join(f"{option['value']}-{option['label']}" for option in enum_values)
                marked_sql.append(f"-- @enum: {field_name} {enum_str}")
            marked_sql.append("")  # 添加一个空行
            marked_sql.append(sql_to_process)

            # 保存处理结果
            bera.logger.debug("保存处理结果")

            # 保存原始SQL文件
            original_file = output_dir / "origin.auto.sql"
            original_file.write_text("\n".join(marked_sql), encoding='utf-8')
            bera.logger.debug(f"保存原始SQL文件: {original_file}")

            # 保存标记信息到配置目录
            mark_file = config_dir / "mark.json"
            mark_data = {
                "table": result.table,
                "columns": result.columns
            }
            SQLFileUtils.write_json_file(mark_file, mark_data, verbose=args.verbose)
            bera.logger.debug(f"保存标记信息: {mark_file}")

            # 保存格式化后的SQL
            formatted_file = output_dir / "formatted.auto.sql"
            formatted_file.write_text(result.cleaned_sql, encoding='utf-8')
            bera.logger.debug(f"保存格式化SQL文件: {formatted_file}")

        except Exception as e:
            SQLFileUtils.handle_file_error(e, Path(filepath), f"处理表 {table_name} 失败")
            raise